<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../assert_selection.js"></script>
<script src="spellcheck_test.js"></script>

<script>
test(() => assert_not_equals(window.internals, undefined),
     'This test requires internals to inspect INPUT elements.');

test(() => assert_not_equals(window.eventSender, undefined),
     'This test requires event sender to simulate keyboard and mouse actions.');

const kNumTests = 5;
const heldTest = async_test(
    () => assert_true(true),
    'Dummy async test for blocking test harness.',
    {finishCount: 0});

add_result_callback(testObj => {
  if (!testObj.properties.blockHeldTest)
    return;
  testObj.properties.sample.remove();
  if (++heldTest.properties.finishCount === kNumTests)
    heldTest.done();
});

function findTextNode(node) {
  if (node.nodeName !== 'INPUT' && node.nodeName !== 'TEXTAREA')
    return node.firstChild;
  return internals.innerEditorElement(node).firstChild;
}

function assertContextClickSelection(
    container, offset, expected, title, opt_suggestion) {
  const document = container.ownerDocument;
  const textNode = findTextNode(container);
  const range = document.createRange();
  range.setStart(textNode, offset);
  // Clear mouse button states from last runs.
  eventSender.setMouseButtonState(-1, []);

  const rect = range.getClientRects()[0];
  const x = document.offsetLeft + rect.left + 2;
  const y = document.offsetTop + rect.top + rect.height / 2;
  eventSender.mouseMoveTo(x, y);
  const contextMenuElements = eventSender.contextClick();

  // Esc key to hide the context menu.
  eventSender.keyDown('Escape', null);

  assert_equals(document.getSelection().toString(), expected, title);

  if (opt_suggestion === undefined)
    return;
  const expectedSuggestion = opt_suggestion !== ''
                           ? opt_suggestion
                           : '<separator>';
  assert_equals(contextMenuElements[contextMenuElements.length - 1],
                expectedSuggestion);
}

function isMac(platform) {
  return platform.includes('Mac');
}

spellcheck_test(
    '<input type="text" value="wellcome home.">',
    document => document.querySelector('input').focus(),
    '<input type="text" value="#wellcome# home.">',
    {
      title: 'Mark misspelling in the initial text of INPUT.',
      callback: sample => test(() => {
        const container = sample.document.querySelector('input');
        assertContextClickSelection(
            container, 4, 'wellcome',
            'Context clicking "wellcome" selects the misspelled word');

        const shouldSelect = isMac(navigator.platform);
        if (shouldSelect) {
          assertContextClickSelection(
              container, 11, 'home',
              'Context clicking "home" selects the correctly spelled word');
          return;
        }
        assertContextClickSelection(
            container, 11, '',
            'Context clicking "home" does not select the correctly spelled word');
      },
      'Context clicking misspelled word in INPUT selects the word.',
      {sample: sample, blockHeldTest: true})
    });

spellcheck_test(
    '<div contenteditable>wellcome home.|</div>',
    '',
    '<div contenteditable>#wellcome# home.</div>',
    {
      title: 'Context click at boundary of misspelled word.',
      callback: sample => test(() => {
        const container = sample.document.querySelector('div');
        assertContextClickSelection(
            container, 0, 'wellcome',
            'Context clicking immediately before "wellcome" selects it');

        // De-select "wellcome" to ensure that context-clicking immediately after
        // "wellcome" will select it again.
        container.ownerDocument.getSelection().removeAllRanges();

        // Right-clicking immediately after a word will select the whole word.
        assertContextClickSelection(
            container, 8, 'wellcome',
            'Context clicking immediately after "wellcome" selects it');
      },
      'Context clicking immediately before or after misspelled word in editable DIV does not select it.',
      {sample: sample, blockHeldTest: true})
    });

spellcheck_test(
    '<div contenteditable>wellcome home.|</div>',
    '',
    '<div contenteditable>#wellcome# home.</div>',
    {
      title: 'Mark initial misspelling "wellcome" in editable DIV.',
      callback: sample => test(() => {
        const container = sample.document.querySelector('div');
        assertContextClickSelection(
            container, 4, 'wellcome',
            'Context clicking "wellcome" selects the misspelled word',
            'welcome');

        const shouldSelect = isMac(navigator.platform);
        if (shouldSelect) {
          assertContextClickSelection(
              container, 11, 'home',
              'Context clicking "home" selects the correctly spelled word', '');
          return;
        }
        assertContextClickSelection(
            container, 11, '',
            'Context clicking "home" does not select the correctly spelled word',
            '');
      },
      'Context clicking misspelled word in editable DIV selects the word.',
      {sample: sample, blockHeldTest: true})
    });

spellcheck_test(
    '<div contenteditable>Helllo wordl.|</div>',
    '',
    '<div contenteditable>#Helllo# #wordl#.</div>',
    {
      title: 'Mark initial misspelling "Helllo" and "wordl" in editable DIV.',
      callback: sample => test(() => {
        const container = sample.document.querySelector('div');
        assertContextClickSelection(
            container, 9, 'wordl',
            'Context clicking "wordl" selects the misspelled word.');
      },
      'Context clicking the second misspelled word "wordl" in editable DIV selects the word.',
      {sample: sample, blockHeldTest: true})
    });

spellcheck_test(
    '<div contenteditable>It should be upper case.|</div>',
    '',
    '<div contenteditable>It should be #upper case#.</div>',
    {
      title: 'Mark initial multi-word misspelling "upper case" in editable DIV.',
      callback: sample => test(() => {
        const container = sample.document.querySelector('div');
        assertContextClickSelection(
            container, 17, 'upper case',
            'Context clicking "upper case" selects the misspelling.',
            'uppercase');
      },
      'Context clicking multi-word misspelling "upper case" in editable DIV selects the words.',
      {sample: sample, blockHeldTest: true})
    });
</script>
